package com.cyy.algovis

import javafx.application.Application
import javafx.beans.property.SimpleObjectProperty
import javafx.geometry.Orientation
import javafx.scene.Group
import javafx.scene.paint.Color
import  tornadofx.*
import kotlin.math.max

class 分形图V : View("分形图的绘制") {
    val x = doubleProperty()
    val y = doubleProperty()
    val widthh = doubleProperty()
    val heightt = doubleProperty()
    val depth = intProperty()
    val maxDepth = intProperty()
    lateinit var g: Group
    val color=SimpleObjectProperty(this, "color", MyColor.Indigo)
    val fractal = SimpleObjectProperty(this, "fractal", FractalShape.Rectangle)

    override val root = borderpane {
        fun draw(fs:FractalShape){
            center?.getChildList()?.clear()
            fs.drawFractal(g,
                    x.value,
                    y.value,
                    widthh.value,
                    heightt.value,
                    depth.value,
                    maxDepth.value,
                    color.value)
        }
        style = "-fx-font-size: 14pt; "
        top = vbox(5) {
            form {
                fieldset(labelPosition = Orientation.VERTICAL) {
                    hbox(5) {
                        field("x:") {
                            textfield(x) {
                                text = "10"
                            }
                        }
                        field("y:") {
                            textfield(y) {
                                text = "10"
                            }
                        }
                        field("widthh:") {
                            textfield(widthh) {
                                text = "800"
                            }
                        }
                        field("heightt:") {
                            textfield(heightt) {
                                text = "400"
                            }
                        }
                        field("depth:") {
                            textfield(depth) {
                                text = "1"
                            }
                        }
                        field("maxDepth:") {
                            textfield(maxDepth) {
                                text = "5"
                            }
                        }
                    }
                    hbox(5) {
                        field("color:") {
                            combobox(property = color, values = MyColor.all)
                        }
                        field("depth:") {
                            combobox(property = depth, values = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))
                        }
                        field("maxDepth:") {
                            combobox(property = maxDepth, values = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))
                        }
                        field("FractalShape:") {
                            combobox(
                                    property = fractal,
                                    values = FractalShape.all
                            ) {
                                selectionModel.selectedItemProperty().addListener { _, _, _ ->
                                    selectionModel.selectedItem?.let {
                                        run{
                                            draw(it)
                                        }
                                    }
                                }
                            }
                        }

                        field(""){
                            togglegroup {
                                FractalShape.values().forEach { fs->
                                    radiobutton(fs.name){
                                        action{
                                            run{
                                                draw(fs)
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                prefWidth = 200.0
            }
        }
        center = group {
            g = this
        }
        prefHeight = 800.0
        prefWidth = 1000.0
    }
}
enum class MyColor(val color:Color) {
    Red(Color.RED),Blue(Color.BLUE),Indigo(Color.INDIGO),Yellow(Color.YELLOW);
    companion object {
        val all by lazy { values().toList() }
    }
}
enum class FractalShape {
    Rectangle {
        tailrec override fun drawFractal(g: Group, x: Double, y: Double, w: Double, h: Double, depth: Int, maxDepth: Int,color:MyColor) {
            if (depth == maxDepth) {
                g.run {
                    add(
                            rectangle(x, y, w, h) {
                                fill = color.color
                            }
                    )
                }
                return
            }
            if ((w <= 1).and(h <= 1)) {
                g.run {
                    add(
                            rectangle(x, y, max(w, 1.0), max(h, 1.0)) {
                                fill = color.color
                            }
                    )
                }
                return
            }
            val w_3 = w / 3
            val h_3 = h / 3
            drawFractal(g, x, y, w_3, h_3, depth + 1, maxDepth,color)
            drawFractal(g, x + 2 * w_3, y, w_3, h_3, depth + 1, maxDepth,color)
            drawFractal(g, x + w_3, y + h_3, w_3, h_3, depth + 1, maxDepth,color)
            drawFractal(g, x, y + 2 * h_3, w_3, h_3, depth + 1, maxDepth,color)
            drawFractal(g, x + 2 * w_3, y + 2 * h_3, w_3, h_3, depth + 1, maxDepth,color)
            return
        }
    },
    Circle {
        tailrec override fun drawFractal(g: Group, x: Double, y: Double, w: Double, h: Double, depth: Int, maxDepth: Int,color:MyColor) {
            if (depth == maxDepth) {
                g.run {
                    add(
                            circle(x, y, w) {
                                fill = color.color
                            }
                    )
                }
                return
            }
            if (w <= 1) {
                g.run {
                    add(
                            circle(x, y, max(w, 1.0)) {
                                fill = color.color
                            }
                    )
                }
                return
            }

            val w_3 = w / 3
            val h_3 = h / 3
            drawFractal(g, x, y, w_3, h_3, depth + 1, maxDepth,color)
            drawFractal(g, x + 2 * w_3, y, w_3, h_3, depth + 1, maxDepth,color)
            drawFractal(g, x + w_3, y + h_3, w_3, h_3, depth + 1, maxDepth,color)
            drawFractal(g, x, y + 2 * h_3, w_3, h_3, depth + 1, maxDepth,color)
            drawFractal(g, x + 2 * w_3, y + 2 * h_3, w_3, h_3, depth + 1, maxDepth,color)
            return
        }
    },
    Ellipse {
        tailrec override fun drawFractal(g: Group, x: Double, y: Double, w: Double, h: Double, depth: Int, maxDepth: Int,color:MyColor) {
            if (depth == maxDepth) {
                with(g) {
                    add(
                            ellipse(x, y, w, h) {
                                fill = color.color
                            }
                    )
                }
                return
            }
            if ((w <= 1).and(h <= 1)) {
                g.run {
                    add(
                            ellipse(x, y, max(w, 1.0), max(h, 1.0)) {
                                fill = color.color
                            }
                    )
                }
                return
            }

            val w_3 = w / 3
            val h_3 = h / 3
            drawFractal(g, x, y, w_3, h_3, depth + 1, maxDepth,color)
            drawFractal(g, x + 2 * w_3, y, w_3, h_3, depth + 1, maxDepth,color)
            drawFractal(g, x + w_3, y + h_3, w_3, h_3, depth + 1, maxDepth,color)
            drawFractal(g, x, y + 2 * h_3, w_3, h_3, depth + 1, maxDepth,color)
            drawFractal(g, x + 2 * w_3, y + 2 * h_3, w_3, h_3, depth + 1, maxDepth,color)
            return
        }
    };

    companion object {
        val all by lazy { values().toList() }
    }

    abstract fun drawFractal(g: Group, x: Double, y: Double, w: Double, h: Double, depth: Int, maxDepth: Int,color:MyColor)
}